package cn.com.doone.common.uc.infrastructure.ldap;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;

import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.BasicAttributes;
import javax.naming.directory.ModificationItem;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.LdapContext;

import org.apache.shiro.realm.ldap.LdapUtils;
import org.springframework.stereotype.Repository;

import cn.com.doone.common.uc.domain.rs.IOAuthRSLdapRepository;
import cn.com.doone.common.uc.infrastructure.jdbc.AbstractLdapRepository;
import cn.com.doone.common.uc.utils.PasswordUtils;

@Repository("oAuthRSLdapRepository")
public class OAuthRSLdapRepository extends AbstractLdapRepository implements IOAuthRSLdapRepository {
	
	@Override
	public Map<String, Object> getUserInfo(String clientId, final String username) {
		
		Map<String, Object> resultMap = new HashMap<String, Object>();
	    
		LdapContext ldapContext = null;
        try {
        	ldapContext = ldapContextFactory.getSystemLdapContext();
			
			final SearchControls searchCtls = new SearchControls(SearchControls.SUBTREE_SCOPE, 1, 0, null, false, false); 
			// final SearchControls searchCtls = new SearchControls(); 
            final NamingEnumeration<SearchResult> search = ldapContext.search("DC=doone,DC=com,DC=cn", "(uid=" + username + ")", searchCtls);
            
            System.out.println("获取信息start：~~~~~~~~~~~~~~~~~~~");
            
            if (search.hasMore()) {
                final SearchResult next = search.next();
                
                resultMap.put("username", next.getAttributes().get("uid").get().toString());
                resultMap.put("realname", next.getAttributes().get("realname").get().toString());
                resultMap.put("nickname", next.getAttributes().get("displayName").get().toString());
                resultMap.put("dc", next.getAttributes().get("ou").get().toString());
                NamingEnumeration<String> ou = (NamingEnumeration<String>) next.getAttributes().get("ou").getAll();
                
                System.out.println("username：" + next.getAttributes().get("uid").get().toString());
                System.out.println("realname：" + next.getAttributes().get("realname").get().toString());
                System.out.println("nickname：" + next.getAttributes().get("displayName").get().toString());
                System.out.println("dc：" + next.getAttributes().get("ou").get().toString());
                
                List<String> ouList = new ArrayList<String>();
                
                while (ou.hasMore()) {
                	 String ouName = (String) ou.next();
                	 ouList.add(ouName);
                }
                resultMap.put("tenantCode", ouList);
                
            }
            
            System.out.println("获取信息end：~~~~~~~~~~~~~~~~~~~");
        } catch (NamingException ne) {
        	ne.printStackTrace();
        } finally {
            LdapUtils.closeContext(ldapContext);
        }
        
	    return resultMap;

	}
	
	public void addUser(String username, Map<String, Object> newUser) {
		
		LdapContext ldapContext = null;
		try {
			ldapContext = ldapContextFactory.getSystemLdapContext();
			String newUsername = (String) newUser.get("username");
			String newPassword = (String) newUser.get("password");
			String nickname = (String) newUser.get("nickname");
			
			String orgDN = getOrgDN(username);
			
			String distinguishedName = "CN=" + newUsername + "," + orgDN;
            Attributes newAttributes = new BasicAttributes(true);
            Attribute oc = new BasicAttribute("objectclass");

            oc.add("top");   
            oc.add("account");
            oc.add("xdwAccount");
            newAttributes.put(oc);   
            newAttributes.put(new BasicAttribute("uid", newUsername));   
            newAttributes.put(new BasicAttribute("displayName", nickname));
            newAttributes.put(new BasicAttribute("cn", nickname));
            newAttributes.put(new BasicAttribute("userPassword", PasswordUtils.openLdapMD5(newPassword)));
            
            ldapContext.createSubcontext(distinguishedName, newAttributes);
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println("Exception in add():" + e);
		} finally {
            LdapUtils.closeContext(ldapContext);
        }
		
	}
	
	/**
	 * 获取账号所在的节点
	 * 
	 * @param username
	 * @return
	 */
	public String getOrgDN(String username) {
		
		String orgDN = "";
		LdapContext ldapContext = null;
        try {
        	ldapContext = ldapContextFactory.getSystemLdapContext(); // .getLdapContext(upToken.getUsername(), upToken.getPassword());
			
			final SearchControls searchCtls = new SearchControls(SearchControls.SUBTREE_SCOPE, 1, 0, null, false, false); 
			// final SearchControls searchCtls = new SearchControls(); 
            final NamingEnumeration<SearchResult> search = ldapContext.search("DC=doone,DC=com,DC=cn", "(uid=" + username + ")", searchCtls);
            
            if (search.hasMore()) {
                final SearchResult next = search.next();
                
                String fullname = next.getNameInNamespace();
                orgDN = fullname.substring(fullname.indexOf(",") + 1, fullname.length());
	        	
            } 
        } catch (NamingException ne) {
        	ne.printStackTrace();
        } finally {
            LdapUtils.closeContext(ldapContext);
        }
		
		return orgDN;
	}
	
	/*private LdapContext getContext() throws NamingException {
		
		String keystore = Thread.currentThread().getContextClassLoader().getResource("/").getPath() + File.separator + "truststore.jks";  
        System.setProperty("javax.net.ssl.trustStore", keystore);
		Hashtable<String, String> ldapEnv = new Hashtable<String, String>(11);
		ldapEnv.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
		// ldapEnv.put(Context.PROVIDER_URL,  "ldap://192.168.100.70:389");
		ldapEnv.put(Context.PROVIDER_URL, propertiesUtils.getLadpsUrl());
		ldapEnv.put(Context.SECURITY_AUTHENTICATION, "simple");
		//ldapEnv.put(Context.SECURITY_PRINCIPAL, "cn=administrateur,cn=users,dc=societe,dc=fr");
		ldapEnv.put(Context.SECURITY_PRINCIPAL, propertiesUtils.getLdapUsername());
		ldapEnv.put(Context.SECURITY_CREDENTIALS, propertiesUtils.getLdapPassword());
		ldapEnv.put(Context.SECURITY_PROTOCOL, "ssl");
		// ldapEnv.put(Context.REFERRAL, "follow");
		
		return new InitialLdapContext(ldapEnv, null);
	}*/
	
	public static void main(String [] args) throws NamingException {
		
		LdapContext ldapContext = getContext();
		// searchOU(ldapContext);
		// searchUserByOU(ldapContext);
		// addUser(ldapContext, "lgx", "1q2w3E4R", "OU=新东网科技,DC=doone,DC=com,DC=cn");
		// updateUser(ldapContext, "admin", "OU=新东网科技,DC=doone,DC=com,DC=cn");
		// deleteUser(ldapContext, "test2", "OU=租户一,DC=doone,DC=com,DC=cn");
		// updatePassword(ldapContext, "test3", "1q2w3E4R", "OU=租户一,DC=doone,DC=com,DC=cn");;
		addOU(ldapContext, "Account", "DC=doone,DC=com,DC=cn");
		// addGroup(ldapContext, "公共组件组", "OU=新东网科技,DC=doone,DC=com,DC=cn");
		// deleteOU(ldapContext, "租户二", "DC=doone,DC=com,DC=cn");
		
	}
	
	/*private static void addUser(LdapContext ldapContext, String userName, String password, String dn) {
		try {
			String distinguishedName = "CN=" + userName + "," + dn;   
            Attributes newAttributes = new BasicAttributes(true);   
            Attribute oc = new BasicAttribute("objectClass");
            
            oc.add("top");   
            oc.add("account");
            oc.add("xdwAccount");
            newAttributes.put(oc);   
            newAttributes.put(new BasicAttribute("uid", userName));   
            newAttributes.put(new BasicAttribute("displayName", userName));
            newAttributes.put(new BasicAttribute("cn", userName));
            newAttributes.put(new BasicAttribute("userPassword", "cb8e30682b927f35"));
            
            
            int UF_ACCOUNTDISABLE = 0x0002;  
            int UF_PASSWD_NOTREQD = 0x0020;  
            int UF_NORMAL_ACCOUNT = 0x0200;  
            int UF_PASSWORD_EXPIRED = 0x800000;  
            // Note that you need to create the user object before you can  
            // set the password. Therefore as the user is created with no  
            // password, user AccountControl must be set to the following  
            // otherwise the Win2K3 password filter will return error 53  
            // unwilling to perform.  
            newAttributes.put("userAccountControl", Integer.toString(UF_NORMAL_ACCOUNT  
                    + UF_PASSWD_NOTREQD + UF_PASSWORD_EXPIRED  
                    + UF_ACCOUNTDISABLE));  
            ldapContext.createSubcontext(distinguishedName, newAttributes);
            
            ModificationItem[] mods = new ModificationItem[2];  
            // Replace the "unicdodePwd" attribute with a new value  
            // Password must be both Unicode and a quoted string  
            String newQuotedPassword = "\"" + password + "\"";  
            byte[] newUnicodePassword = newQuotedPassword.getBytes("UTF-16LE");  
            mods[0] = new ModificationItem(LdapContext.REPLACE_ATTRIBUTE, new BasicAttribute("unicodePwd", newUnicodePassword));  
            mods[1] = new ModificationItem(LdapContext.REPLACE_ATTRIBUTE, new BasicAttribute("userAccountControl", Integer.toString(UF_NORMAL_ACCOUNT + UF_PASSWORD_EXPIRED)));  
            // Perform the update  
            ldapContext.modifyAttributes("CN=" + userName + "," + dn, mods);  
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println("Exception in add():" + e);
		} finally {
            LdapUtils.closeContext(ldapContext);
        }
	}*/
	
	private static void updateUser(LdapContext ldapContext, String userName, String dn) {
		try {
			ModificationItem[] mods = new ModificationItem[1];   
			// 替换
	        // mods[0] = new ModificationItem(LdapContext.REPLACE_ATTRIBUTE, new BasicAttribute("userPassword", "4621d373cade4e83"));   
			
			String updateTime = cn.com.doone.common.uc.utils.LdapUtils.Timestamp2generalized(new Timestamp(System.currentTimeMillis()), TimeZone.getTimeZone("CST"));
			
	        mods[0] = new ModificationItem(LdapContext.REPLACE_ATTRIBUTE, new BasicAttribute("updateTime", updateTime));   
	        ldapContext.modifyAttributes("CN=" + userName + "," + dn, mods);
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println("Exception in add():" + e);
		} finally {
            LdapUtils.closeContext(ldapContext);
        }
	}
	
	/*
	private static void updatePassword(LdapContext ldapContext, String userName, String password, String dn) {
		try  {   
            System.out.println("updating password...\n");   
            String quotedPassword = "\"" + password + "\"";   
            byte[] newUnicodePassword = quotedPassword.getBytes("UTF-16LE");   
            System.out.println();   
            ModificationItem[] mods = new ModificationItem[1];
            mods[0] = new ModificationItem(LdapContext.REPLACE_ATTRIBUTE, new BasicAttribute("unicodePwd", newUnicodePassword));   
            ldapContext.modifyAttributes("CN=" + userName + "," + dn, mods);   
        } catch (Exception e) {   
            System.out.println("update password error: " + e);   
            e.printStackTrace();   
            System.exit(-1);   
        } finally {
            LdapUtils.closeContext(ldapContext);
        }
	}
	
	private static void deleteUser(LdapContext ldapContext, String userName, String dn) {
		try {
	        ldapContext.destroySubcontext("CN=" + userName + "," + dn);
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println("Exception in add():" + e);
		} finally {
            LdapUtils.closeContext(ldapContext);
        }
	}*/
	
	/**
	 * 新增租户
	 * 
	 * @param ldapContext
	 * @param ouName
	 * @param dn
	 */
	private static void addOU(LdapContext ldapContext, String ouName, String dn) {
		try {
			String distinguishedName = "OU=" + ouName + "," + dn;   
            Attributes newAttributes = new BasicAttributes(true);   
            Attribute oc = new BasicAttribute("objectClass");   
            oc.add("top");   
            oc.add("xdwOrganization"); 
            newAttributes.put(oc);   
            newAttributes.put(new BasicAttribute("ou", ouName));
            newAttributes.put(new BasicAttribute("dbid", "1"));
            newAttributes.put(new BasicAttribute("groupCode", "TOPOU"));
            newAttributes.put(new BasicAttribute("groupName", "账号"));
            newAttributes.put(new BasicAttribute("groupType", "1"));
            newAttributes.put(new BasicAttribute("tenantCode", "TOPOU"));
            newAttributes.put(new BasicAttribute("status", "1"));
            String updateTime = cn.com.doone.common.uc.utils.LdapUtils.Timestamp2generalized(new Timestamp(System.currentTimeMillis()), TimeZone.getTimeZone("CST"));
            newAttributes.put(new BasicAttribute("updateTime", updateTime));
            
            ldapContext.createSubcontext(distinguishedName, newAttributes);   
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println("Exception in add():" + e);
		} finally {
            LdapUtils.closeContext(ldapContext);
        }
	}
	/*
	*//**
	 * 新增组
	 * 
	 * @param ldapContext
	 * @param ouName
	 * @param dn
	 *//*
	private static void addGroup(LdapContext ldapContext, String ouName, String dn) {
		try {
			String distinguishedName = "cn=" + ouName + "," + dn;   
            Attributes newAttributes = new BasicAttributes(true);   
            Attribute oc = new BasicAttribute("objectClass");   
            oc.add("top");   
            oc.add("xdwGroup"); 
            newAttributes.put(oc);   
            newAttributes.put(new BasicAttribute("CN", ouName));
            newAttributes.put(new BasicAttribute("gidNumber", "0"));
            newAttributes.put(new BasicAttribute("groupCode", "GGZJ"));
            newAttributes.put(new BasicAttribute("groupName", ouName));
            newAttributes.put(new BasicAttribute("groupType", "2"));
            newAttributes.put(new BasicAttribute("tenantCode", "doone.com.cn"));
            newAttributes.put(new BasicAttribute("status", "1"));
            ldapContext.createSubcontext(distinguishedName, newAttributes);   
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println("Exception in add():" + e);
		} finally {
            LdapUtils.closeContext(ldapContext);
        }
	}
	
	private static void deleteOU(LdapContext ldapContext, String ouName, String dn) {
		try {
	        ldapContext.destroySubcontext("OU=" + ouName + "," + dn);
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println("Exception in add():" + e);
		} finally {
            LdapUtils.closeContext(ldapContext);
        }
	}*/
	
	private static void searchUserByOU(LdapContext ldapContext) {
		try {
			
			// final String [] resultProperties = new String[]{"sAMAccountName", "userPrincipalName"};
            final SearchControls searchCtls = new SearchControls(SearchControls.SUBTREE_SCOPE, 1, 0, null, false, false); 
			// final SearchControls searchCtls = new SearchControls(); 
            final NamingEnumeration<SearchResult> search = ldapContext.search("OU=Account,DC=doone,DC=com,DC=cn", "uid=admin", searchCtls);
            
            if (search.hasMore()) {
                final SearchResult next = search.next();
                
                String fullname = next.getNameInNamespace();
                NamingEnumeration<String> ou = (NamingEnumeration<String>) next.getAttributes().get("ou").getAll();
                NamingEnumeration<String> uid = (NamingEnumeration<String>) next.getAttributes().get("uid").getAll();
                
                List<String> ouList = new ArrayList();
                
                while (ou.hasMore()) {
                	 String ouName = (String) ou.next();
                	 ouList.add(ouName);
                }
                
                System.out.println("sdf");
                ldapContext.addToEnvironment(Context.SECURITY_PRINCIPAL, fullname);
                ldapContext.addToEnvironment(Context.SECURITY_CREDENTIALS, "cb8e30682b927f35");
                ldapContext.reconnect(null);
            } 
        } catch (NamingException ne) {
        	ne.printStackTrace();
        } finally {
            LdapUtils.closeContext(ldapContext);
        }
	}
	
	/*
	private static void searchOU(LdapContext ldapContext) {
		try {
			
            // final String [] resultProperties = new String[]{"sAMAccountName", "userPrincipalName", "OU"};
			final SearchControls searchCtls = new SearchControls(SearchControls.SUBTREE_SCOPE, 0, 0, null, false, false); 
            final NamingEnumeration<SearchResult> search = ldapContext.search("DC=doone,DC=com,DC=cn", "objectClass=organizationalUnit", searchCtls);
            
            while(search.hasMore()) {
                final SearchResult next = search.next();
                
                String userPrincipalName = next.getAttributes().get("userPrincipalName").get().toString();
                String name = next.getName();
	        
                System.out.println("sdf");
            } 
        } catch (NamingException ne) {
        	ne.printStackTrace();
        } finally {
            LdapUtils.closeContext(ldapContext);
        }
	}*/
	
	private static LdapContext getContext() throws NamingException {
		
		// String keystore = "I://cacerts/truststore.jks";  
        // System.setProperty("javax.net.ssl.trustStore", keystore);
		Hashtable<String, String> ldapEnv = new Hashtable<String, String>(11);
		ldapEnv.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
		ldapEnv.put(Context.PROVIDER_URL,  "ldap://192.168.100.32:389");
		// ldapEnv.put(Context.PROVIDER_URL, "ldaps://192.168.100.70:636");
		ldapEnv.put(Context.SECURITY_AUTHENTICATION, "simple");
		ldapEnv.put(Context.SECURITY_PRINCIPAL, "cn=Users,dc=doone,dc=com,dc=cn");
		// ldapEnv.put(Context.SECURITY_PRINCIPAL, "root");
		ldapEnv.put(Context.SECURITY_CREDENTIALS, "xiE7usWA");
		// ldapEnv.put(Context.SECURITY_PROTOCOL, "ssl");
		// ldapEnv.put(Context.REFERRAL, "follow");
		
		return new InitialLdapContext(ldapEnv, null);
	}

	@Override
	public void updateUserInfo(Map userMap, String tenantFullName) throws Exception {
		LdapContext ldapContext = null;
		try {
			ldapContext = ldapContextFactory.getSystemLdapContext();
		
			String userAccount = (String) userMap.get("userAccount");
			String nickname = (String) userMap.get("nickname");
			String email = (String) userMap.get("email");
			
			final SearchControls searchCtls = new SearchControls(SearchControls.SUBTREE_SCOPE, 1, 0, null, false, false); 
            final NamingEnumeration<SearchResult> search = ldapContext.search("OU=Account,DC=doone,DC=com,DC=cn", "uid=" + userAccount, searchCtls);
           
            	
        	ModificationItem[] mods = new ModificationItem[3];   
			String updateTime = cn.com.doone.common.uc.utils.LdapUtils.Timestamp2generalized(new Timestamp(System.currentTimeMillis()), TimeZone.getTimeZone("CST"));
			
	        mods[0] = new ModificationItem(LdapContext.REPLACE_ATTRIBUTE, new BasicAttribute("updateTime", updateTime));   
	        mods[1] = new ModificationItem(LdapContext.REPLACE_ATTRIBUTE, new BasicAttribute("displayName", (nickname == null || nickname.isEmpty()) ? userAccount : nickname));   
	        mods[2] = new ModificationItem(LdapContext.REPLACE_ATTRIBUTE, new BasicAttribute("mail", email));
	        
	        ldapContext.modifyAttributes("CN=" + userAccount + ",OU=Account,DC=doone,DC=com,DC=cn", mods);
			
		} catch (Exception e) {
			e.printStackTrace();
			throw e;
		} finally {
            LdapUtils.closeContext(ldapContext);
        }
	}
	
	@Override
	public void updateMobilePhone(Map userMap, String tenantFullName) throws Exception {
		LdapContext ldapContext = null;
		try {
			ldapContext = ldapContextFactory.getSystemLdapContext();
		
			String userAccount = (String) userMap.get("userAccount");
			String mobilePhone = (String) userMap.get("mobilePhone");
			
			final SearchControls searchCtls = new SearchControls(SearchControls.SUBTREE_SCOPE, 1, 0, null, false, false); 
            final NamingEnumeration<SearchResult> search = ldapContext.search("OU=Account,DC=doone,DC=com,DC=cn", "uid=" + userAccount, searchCtls);
           
            	
        	ModificationItem[] mods = new ModificationItem[2];   
			String updateTime = cn.com.doone.common.uc.utils.LdapUtils.Timestamp2generalized(new Timestamp(System.currentTimeMillis()), TimeZone.getTimeZone("CST"));
			
	        mods[0] = new ModificationItem(LdapContext.REPLACE_ATTRIBUTE, new BasicAttribute("updateTime", updateTime));   
	        mods[1] = new ModificationItem(LdapContext.REPLACE_ATTRIBUTE, new BasicAttribute("telephoneNumber", (mobilePhone != null && mobilePhone.isEmpty()) ? null : mobilePhone));

	        
	        ldapContext.modifyAttributes("CN=" + userAccount + ",OU=Account,DC=doone,DC=com,DC=cn", mods);
			
		} catch (Exception e) {
			e.printStackTrace();
			throw e;
		} finally {
            LdapUtils.closeContext(ldapContext);
        }
	}

}
